/*
 * Expr.h
 *
 *  Created on: 2010-12-18
 *      Author: lyyang
 */

#ifndef EXPR_H_
#define EXPR_H_
#include <iostream>
using std::ostream;
using std::string;

class Expr_node;
class Expr {
public:
	void print(ostream& o);
	Expr(int v);
	Expr(string op, Expr opnd);
	Expr(string op, Expr l, Expr r);
	Expr(const Expr& expr);
	~Expr();

	int eval();

private:
	Expr_node* node_;
};

class Expr_node {
friend class Expr;
public:
	virtual void print(ostream& o)=0;
	virtual int eval()=0;
	int use_count_;
};

class Int_node : public Expr_node {
public:
	virtual void print(ostream& o) {
		o << value_;
	}
	virtual int eval() {
		return value_;
	}
	Int_node(int v) : value_(v) {}

private:
	int value_;
};

class Unary_node : public Expr_node {
public:
	virtual void print(ostream& o) {
		o << "(" << op_ << " ";
		opnd_.print(o);
		o << ")";
	}
	virtual int eval() {
		if (op_ == "-") {
			return -1*opnd_.eval();
		} else if (op_ == "+") {
			return opnd_.eval();
		}
	}
	Unary_node(string op0, Expr opnd0) :
		op_(op0), opnd_(opnd0){}

private:
	string op_;
	Expr opnd_;
};

class Binary_node : public Expr_node {
public:
	virtual void print(ostream& o) {
		o << "(" << op_ << " ";
		left_.print(o);
		o << " ";
		right_.print(o);
		o << ")";
	}
	virtual int eval() {
		if (op_ == "-") {
			return left_.eval() - right_.eval();
		} else if (op_ == "+") {
			return left_.eval() + right_.eval();
		} else if (op_ == "*") {
			return left_.eval() * right_.eval();
		}
	}
	Binary_node(string op0, Expr l, Expr r) :
		op_(op0), left_(l), right_(r){}

private:
	string op_;
	Expr left_;
	Expr right_;
};



#endif /* EXPR_H_ */
